package cn.hcbycloud.auth.service;


import cn.hcbycloud.auth.bo.*;
import cn.hcbycloud.auth.mapper.UserMapper;
import cn.hcbycloud.auth.model.Cust;
import cn.hcbycloud.auth.model.CustExtend;
import cn.hcbycloud.auth.model.User;
import cn.hcbycloud.auth.model.UserLogin;
import cn.hcbycloud.common.core.constant.*;
import cn.hcbycloud.common.core.exception.CustomizeException;
import cn.hcbycloud.common.core.utils.ObjectUtils;
import cn.hcbycloud.common.core.utils.PasswordUtil;
import cn.hcbycloud.common.jwt.constant.TokenTypeEnum;
import cn.hcbycloud.common.jwt.service.encryptionkey.BaseGenerateJwtKeyService;
import cn.hcbycloud.common.jwt.service.jwt.JwtBuilderFactory;
import cn.hcbycloud.common.jwt.service.jwt.JwtRedisCacheService;
import cn.hcbycloud.common.jwt.service.jwt.JwtService;
import cn.hcbycloud.common.jwt.vo.JwtToken;
import cn.hcbycloud.common.jwt.vo.LoginInfo;
import cn.hcbycloud.common.mvc.model.AppTenant;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 用户基本信息表
 *
 * @author gaoheng
 * @date 2022-01-18 23:33:57
 */
@Slf4j
@Service
@AllArgsConstructor
public class UserService extends ServiceImpl<UserMapper, User> {
    /**
     * 用户基本信息DAO
     */
    private UserMapper userMapper;
    /**
     * 租户信息服务
     */
    private TenantService tenantService;
    /**
     * 租户客户关系信息服务
     */
    private TenantCustService tenantCustService;
    /**
     * 客户信息服务
     */
    private CustService custService;
    /**
     * 用户认证服务
     */
    private UserLoginService userLoginService;
    /**
     * JWTToken 生成服务
     */
    private JwtService jwtService;
    /**
     * 密钥对
     */
    private BaseGenerateJwtKeyService generateJwtKeyService;
    /**
     * JWT 构造器
     */
    private JwtBuilderFactory jwtBuilder;
    /**
     * JWT令牌对象缓存服务
     */
    private JwtRedisCacheService jwtRedisCacheService;
    /**
     * 角色信息服务
     */
    private RoleService roleService;
    /**
     * 角色关系服务
     */
    private RoleRelationService roleRelationService;
    /**
     * 权限服务
     */
    private PermissionService permissionService;


    /**
     * 个人客户信息注册
     *
     * @param userRegisterBO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public UserRegisterResultBO registerUserOfPersonCust(UserRegisterBO userRegisterBO,String tenantCode) throws Exception {
        // 获取租户信息
        AppTenant tenant = tenantService.getTenantByRequireCode(tenantCode);
        // 获取用户注册的登录信息
        List<UserLogin> userLoginList = userRegisterBO.getUserLoginList();
        // 循环出用户认证名数据列表
        List<String> userNameList = CollUtil.newArrayList();
        for (UserLogin userLogin : userLoginList) {
            userNameList.add(userLogin.getUserName());
        }
        /** 判断用户认证信息是否已经存在*/
        List<UserInfoBO> userInfoBOList = userLoginService.getUserInfoByUserNameList(userNameList, tenant.getTenantId());
        if (CollUtil.isNotEmpty(userInfoBOList)) {
            for (UserInfoBO userInfoBO : userInfoBOList) {
                if (ObjectUtil.isNotNull(UserNameTypeEnum.getUserNameTypeEnum(userInfoBO.getUserNameType()))) {
                    throw new CustomizeException(UserNameTypeEnum.getUserNameTypeEnum(userInfoBO.getUserNameType()).getDesc() + "已存在");
                }
            }
            throw new CustomizeException("该用户注册信息已存在");
        }
        /*开始组装个人客户信息*/
        CustInfoBO custInfoOfPersonBo = this.buildPersonCustomer(userLoginList, userRegisterBO.getUser());
        // 判断客户信息是否已经存在
        if (!custService.haveCustomer(custInfoOfPersonBo.getCust().getMainId(), tenant.getTenantId())) {
            // 新增个人客户信息
            String custOfPersonId = custService.addCustInfo(custInfoOfPersonBo);
            /* 如果存在集团客户对象，说明个人客户注册时挂载了集团客户信息*/
            if (ObjectUtil.isNotNull(userRegisterBO.getCustOfBusinessBo()) &&
                    ObjectUtil.isNotNull(userRegisterBO.getCustOfBusinessBo().getCust())) {
                String custOfBusinessMainId = userRegisterBO.getCustOfBusinessBo().getCust().getMainId();
                // 判断挂载的集团客户信息是否存在
                if (custService.haveCustomer(custOfBusinessMainId, tenant.getTenantId())) {
                    log.info("如集团客户存在，则将新增的个人客户信息挂载到集团客户下");
                    // TODO 建立个人客户与集团客户关系数据
                } else {
                    throw new CustomizeException("注册的企业信息不存在");
                }
            }
            // 建立客户租户关系
            tenantCustService.addTenantCustInfo(new TenantCustBO(tenant.getTenantId(), custOfPersonId));
            // 新增用户基本信息,建立个人客户与用户关系
            UserInfoBO userInfoBo = this.addUserInfo(userRegisterBO.getUser(), custOfPersonId);
            // 新增用户认证信息
            userLoginService.addUserLoginInfo(userRegisterBO.getUserLoginList(), userInfoBo.getUserId());
            // 生成JWTToken对象
            JwtToken jwtToken = jwtService.generateToken(new LoginInfo(userInfoBo.getUserId(),
                    custOfPersonId,tenant.getTenantId(), TokenTypeEnum.USER_TYPE.getType()),
                    generateJwtKeyService, jwtBuilder);
            // 将JWT令牌存入缓存
            jwtRedisCacheService.setTokenToCache(jwtToken);
            // 给新注册的用户配置角色
            List<RoleBO> roleBoList = null;
            if (CollUtil.isNotEmpty(userRegisterBO.getRoleCodes())) {
                roleBoList = roleService.getRolesByCodes(userRegisterBO.getRoleCodes(), tenant.getTenantId());
                RoleRelationBO roleRelationBo = new RoleRelationBO(userInfoBo.getUserId(),
                        RoleMainIdTypeEnum.ROLE_MAIN_ID_USER_TYPE.getCode(), roleBoList);
                roleRelationService.addRoleRelationInfo(roleRelationBo, tenant.getTenantId());
            }
            // 返回角色对应的权限及资源对象
            PermissionContainResourceBO permissionContainResourceBo = permissionService
                    .getPermissionContainResourceByRoles(roleBoList, tenant.getTenantId());
            return new UserRegisterResultBO(userInfoBo.getName(), userInfoBo.getNickname(), userInfoBo.getPhoto(),
                    jwtToken.getToken(), roleBoList, permissionContainResourceBo);
        } else {
            throw new CustomizeException("该用户所属客户信息已存在");
        }
    }

    /**
     * 新增用户信息
     *
     * @param user
     * @param custId
     * @return
     */
    public UserInfoBO addUserInfo(User user, String custId) throws Exception {
        user.setCustId(custId);
        user.preInsert();
        // 判断用户密码是否为空，如不为空，需要进行加密
        if (StrUtil.isNotBlank(user.getPassword())) {
            // 生成随机盐
            String salt = PasswordUtil.getRandomString(5);
            // 密码加密
            user.setPassword(PasswordUtil.getMd5(user.getPassword(), salt));
            user.setSalt(salt);
        }
        userMapper.insert(user);
        UserInfoBO userInfoBO = ObjectUtils.cloneObject(user, UserInfoBO.class);
        userInfoBO.setUserId(user.getId());
        return userInfoBO;
    }

    /**
     * 组装个人客户信息
     *
     * @param userLoginList
     * @return
     */
    private CustInfoBO buildPersonCustomer(List<UserLogin> userLoginList, User user) {
        Cust cust = new Cust();
        cust.setCustType(CustomerTypeEnum.CUSTOMER_TYPE_PERSON.getCode());
        // 将用户基本信息的姓名作为个人客户名称
        cust.setCustName(user.getName());
        CustExtend custExtend = new CustExtend();
        for (UserLogin userLogin : userLoginList) {
            // 用户唯一标识为身份证号码
            if (StrUtil.equals(userLogin.getUserNameType(), UserNameTypeEnum.USER_ID_CARD_TYPE.getCode())) {
                // 将身份证号码设置为个人客户主体标识
                cust.setMainId(userLogin.getUserName());
                // 设置主体标识类型为身份证
                cust.setMainType(CustMainIdTypeEnum.CUST_ID_CARD_TYPE.getCode());
                // 将身份证号设置为客户证件号码
                custExtend.setCredentialsCode(userLogin.getUserName());
                // 设置客户证件类型
                custExtend.setCredentialsType(CredentialsTypeEnum.LEGAL_PERSON_ID_CARD_TYPE.getCode());
            }
            // 用户唯一标识为手机号
            if (StrUtil.equals(userLogin.getUserNameType(), UserNameTypeEnum.USER_MOBILE_PHONE_TYPE.getCode())) {
                // 设置客户联系人手机号
                custExtend.setLinkmanPhone(userLogin.getUserName());
            }
            // 用户唯一标识为邮箱
            if (StrUtil.equals(userLogin.getUserNameType(), UserNameTypeEnum.USER_MAIL_TYPE.getCode())) {
                // 设置客户联系邮箱
                custExtend.setLinkmanMail(userLogin.getUserName());
            }
        }
        return new CustInfoBO(cust, custExtend);
    }

}
